#include<fstream>
#include<iostream>
#include<vector>
#include<algorithm>
#include<sstream>
#include<cmath>
#include<string>
#include <stdexcept>
#include <sstream>
using namespace std;

const double EPSILON = 1.0e-9; //误差范围，用于double数之间的比较
int compare_double(double a, double b)     //浮点数double比较函数，如果a>b，返回1，a==b，返回0，a<b，返回-1
{
    return (a-b) > EPSILON ? 1 : ((a-b) < -EPSILON ? -1 : 0);
}

void check_legal_line(vector<string>& subs,int &category, double &value)
{
	if (subs.size() < 2) {
        throw runtime_error("数据格式错误: 每行需要至少两个字段");
    }

    // 解析分类标识
    if (subs[0] == "Vth")       category = 2;
    else if (subs[0] == "Tsim") category = 3;
    else if (subs[0] == "dT")   category = 1;
    else {
        throw runtime_error("未知标识: " + subs[0]);
    }

    // 解析数值
    try {
        size_t pos;
        value = stod(subs[1], &pos);
        if (pos != subs[1].size()) {
            throw invalid_argument(""); // 触发catch块
        }
    } 
	catch (const exception& e) {
        throw std::runtime_error("Invalid input ");
		return;
    }
	size_t has_dot = subs[1].find('.');	//数值可以只以单小数点的形式给出，也可以只以e指数形式给出，也可以结合}

	size_t has_e = subs[1].find('e');
	if(has_dot!=subs[1].npos&&has_e==subs[1].npos)	//只有小数点，则左右两把必须有数字且仅有数字
	{
		string _integer = string(subs[1],0,has_dot);
		if(_integer.empty()||!all_of(_integer.begin(), _integer.end(), ::isdigit))
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		int integer = stoi(_integer);	//整数部分
		if(has_dot==subs[1].size()-1||has_dot==0)	//没有小数，整数，则报错
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		double decimal = 0;		//获得小数部分
		for(size_t j=has_dot+1;j<subs[1].size();j++)
		{
			if(subs[1][j]>'9'|| subs[1][j]<'0')
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			decimal += (double)(subs[1][j] - '0') / pow(10,j-has_dot);
		}
		value = decimal + integer;	//相加
		return;
	}
	if(has_dot==subs[1].npos&&has_e!=subs[1].npos)	//只有指数
	{
		string _base = string(subs[1],0,has_e);
		if(_base.empty()|| !all_of(_base.begin(), _base.end(), ::isdigit))
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		int base = stoi(_base);
		if(has_e==subs[1].size()-1||has_e==0)	//指数底数都不应该为空
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		string __pow = string(subs[1],has_e+1);
		if(__pow[0]=='-')	//考虑负指数的情况
		{
			if(__pow.size()==1)
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			string __num = string(__pow,1);
			if(!all_of(__num.begin(), __num.end(), ::isdigit))
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			int num = stoi(__num);
			value = base;
			for(int p=0;p<num;p++) value/=10.0;
			return;
		}
		else	//正指数的情况
		{
			if(!all_of(__pow.begin(), __pow.end(), ::isdigit))
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			int num = stoi(__pow);
			value = base;
			for(int p=0;p<num;p++) value*=10.0;
			return;
		}
	}
	if(has_dot==subs[1].npos&&has_e==subs[1].npos)	//若都无，则应该全为数字，即为一个整数
	{
		if(!all_of(subs[1].begin(), subs[1].end(), ::isdigit))
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		value = (double)stoi(subs[1]);
		return;
	}
	if(has_dot!=subs[1].npos&&has_e!=subs[1].npos)	//都有，则考虑分割考虑底数的整数部分，小数部分和指数部分
	{
		if(has_dot>has_e || has_dot+1 == has_e || has_dot == 0 ||has_e == subs[1].size()-1)	//小数点和e指数的位置不能反
		{
			throw std::runtime_error("非法输入" );
			return;
		}
		string _base_integer  = string(subs[1],0,has_dot);
		string _base_demical = string(subs[1],has_dot+1,has_e-has_dot-1);	
		string _expo = string(subs[1],has_e+1);
		//考虑底数的格式是否正确
		if(!all_of(_base_integer.begin(), _base_integer.end(), ::isdigit) || !all_of(_base_demical.begin(), _base_demical.end(), ::isdigit))
		{
			throw std::runtime_error("非法输入" );
			return;
		}

		
		int integer = stoi(_base_integer);
		double decimal = 0;
		for(size_t j=0;j<_base_demical.size();j++)
		{
			decimal += (double)(_base_demical[j] - '0') / pow(10,j+1);
		}
		double _base = decimal + integer;	//获得底数
		//获得指数
		if(_expo[0]=='-')
		{
			if(_expo.size()==1)
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			string __num = string(_expo,1,_expo.size()-1);
			if(!all_of(__num.begin(), __num.end(), ::isdigit))
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			int num = stoi(__num);
			value = _base;
			for(int p=0;p<num;p++) value/=10.0;
			return;
		}
		else
		{
			if(!all_of(_expo.begin(), _expo.end(), ::isdigit))
			{
				throw std::runtime_error("非法输入" );
				return;
			}
			int num = stoi(_expo);
			value = _base;
			for(int p=0;p<num;p++) value*=10.0;
			return;
		}

	}
	
}

string trimLeft(const string& str) {	//剔除每行内容左端的空白字符
    size_t start = 0;
    
    while (start < str.length() && isspace(str[start])) {
        ++start;
    }
    return str.substr(start);
}
vector<string> split(const string& str) {	//将每行以空白字符为间隔分割开
    vector<string> result;
    string temp;
    istringstream stream(str);

    while (stream >> temp) {
        result.push_back(temp);
    }

    return result;
}

void readFile(double &dt, double &vth, double &tsim, const string& filename)         //从文件中读取器件数据
{   
	ifstream infile;
	infile.open(filename);
	if (!infile.is_open()) {
        // 手动抛出异常
        throw std::runtime_error("无法打开文件: " + filename);
		return;
    }
    string buf;
	string name;
	
	int category;
	double value;
    vector<string> subs;
    buf.clear();
    while (getline(infile, buf)) //
    {  
        buf = trimLeft(buf);	//清空开头的空字符
		if(!buf.empty())
		{
			subs.clear();
			subs = split(buf);	//分割空格获得子串
			try {
                check_legal_line(subs, category, value); // 可能抛出异常
            } catch (const runtime_error& e) {
                // 添加行号信息后重新抛出
                throw_with_nested(
                    runtime_error(" 错误行: " + buf + "\n" + e.what())
            );
			}
			{
				switch (category)                       //
        		{
        			case 1:
						dt = value;
            			break;
        			case 2:
						vth = value;
            			break;
        			case 3:
						tsim = value;
            			break;
        		}
			}
		}
		buf.clear();
    }
	
	if (compare_double(dt,0) < 0||compare_double(dt,0.1) >= 0|| compare_double(vth,0) <= 0|| compare_double(vth,1) >= 0||compare_double(tsim,0) <= 0) {
		std::ostringstream oss;
		oss << "Invalid parameter value: \ndT=" << std::scientific << dt 
			<< ", \nVth=" << vth 
			<< ", \nTsim=" << tsim;
		throw std::runtime_error(oss.str());
	}

    infile.close();  //
}


